package com.cloudfun.campusshare.service.impl;

import com.cloudfun.campusshare.common.constant.Code;
import com.cloudfun.campusshare.common.constant.RoleType;
import com.cloudfun.campusshare.common.exception.BusinessException;
import com.cloudfun.campusshare.common.security.AuthenticationHolder;
import com.cloudfun.campusshare.entity.UserEntity;
import com.cloudfun.campusshare.entity.UserRelEntity;
import com.cloudfun.campusshare.repo.UserEntityRepo;
import com.cloudfun.campusshare.repo.UserRelEntityRepo;
import com.cloudfun.campusshare.service.RoleService;
import com.cloudfun.campusshare.service.UserRelService;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by Huqin on 2020/5/9
 */
@Slf4j
@Service
public class UserRelServiceImpl implements UserRelService {

    @Autowired
    private UserRelEntityRepo userRelEntityRepo;

    @Autowired
    private UserEntityRepo userEntityRepo;

    @Autowired
    private RoleService roleService;

    @Override
    public void create(UserRelEntity userRelEntity) {
        UserRelEntity userRel = userRelEntityRepo.findByParentIdAndUserId(userRelEntity.getParentId(), userRelEntity.getUserId());
        if (null != userRel) {
            throw new BusinessException(Code.DATA_EXIST, "账号关联关系已存在");
        }
        userRelEntityRepo.save(userRelEntity);
    }

    @Override
    public UserEntity getUserMerchant(String userId) {
        Set<String> userRoleTypes = roleService.getRoleTypes(userId);
        // 如果UserId对应的用户是管理员、运营商、平台商，直接使用UserId查询并返回
        if (userRoleTypes.contains(RoleType.OPERATIONAL_MERCHANT.name())
                || userRoleTypes.contains(RoleType.PLATFORM_MERCHANT.name())
                || userRoleTypes.contains(RoleType.ADMIN.name())) {
            return userEntityRepo.findById(userId).orElseThrow(() -> new BusinessException(Code.NODATA));
        }
        // 否则查询该用户所属运营商并返回
        UserEntity userEntity = userEntityRepo.findById(userId).orElseThrow(() -> new BusinessException(Code.NODATA));
        if (StringUtils.isBlank(userEntity.getMerchantId())) {
            return null;
        }
        return userEntityRepo.findById(userEntity.getMerchantId()).orElseThrow(() -> new BusinessException(Code.NODATA));
    }

    @Override
    public Set<String> getDescendantIds(String userId) {
        String merchantId;
        if (AuthenticationHolder.isMerchant()) {
            merchantId = AuthenticationHolder.getUserId();
        } else {
            UserEntity userEntity = userEntityRepo.findById(userId).orElseThrow(() -> new BusinessException(Code.NODATA));
            merchantId = userEntity.getMerchantId();
        }
        if (StringUtils.isBlank(merchantId)) {
            return new HashSet<>();
        }
        List<UserRelEntity> relList = userRelEntityRepo.findAllByMerchantId(merchantId);
        relList = relList.stream().filter(e -> !StringUtils.equals(e.getUserId(),e.getParentId())).collect(Collectors.toList());
        Node rootNode = new Node("-1", merchantId, new ArrayList<>());
        List<Node> parentNodeList = relList.stream()
                .map(rel -> new Node(rel.getParentId(), rel.getUserId(), new ArrayList<>()))
                .peek(node -> {
                    if (node.getParentId().equals(merchantId)) {
                        rootNode.getChild().add(node);
                    }
                })
                .collect(Collectors.toList());
        Map<String, List<Node>> parentNodesMap = parentNodeList.stream().collect(Collectors.groupingBy(Node::getParentId));
        for (Node node : parentNodeList) {
            node.setChild(parentNodesMap.getOrDefault(node.getId(), new ArrayList<>()));
        }

        List<String> descendantIds = Node.getDescendantIds(userId, rootNode);
        return new HashSet<>(descendantIds);
    }

    @Override
    public void deleteByUserId(String id) {
        // 将其在父节点删除
        UserRelEntity byUserId = userRelEntityRepo.findByUserId(id);
        if (null == byUserId) {
            return;
        }
        userRelEntityRepo.delete(byUserId);

        // 将子节点转移到父节点下
        List<UserRelEntity> child = userRelEntityRepo.findAllByParentId(id);
        if (CollectionUtils.isEmpty(child)) {
            return;
        }
        for (UserRelEntity userRelEntity : child) {
            userRelEntity.setParentId(byUserId.getParentId());
        }
        userRelEntityRepo.saveAll(child);
    }

    @Data
    @AllArgsConstructor
    static class Node {
        String parentId;
        String id;
        List<Node> child;

        /**
         * 获取指定节点
         *
         * @param id
         * @param root
         * @return
         */
        public static Node getNode(String id, Node root) {
            if (root == null) {
                return null;
            }
            if (root.getId().equals(id)) {
                return root;
            }
            for (Node node : root.getChild()) {
                Node res = getNode(id, node);
                if (null != res) {
                    return res;
                }
            }
            return null;
        }

        /**
         * 获取指定节点子孙节点的id集合
         *
         * @param id
         * @param root
         * @return
         */
        public static List<String> getDescendantIds(String id, Node root) {
            List<Node> descendantNodes = getDescendantNodes(id, root);
            return descendantNodes.stream().map(Node::getId).collect(Collectors.toList());
        }

        /**
         * 获取指定节点的子孙节点
         *
         * @param id
         * @param root
         * @return
         */
        public static List<Node> getDescendantNodes(String id, Node root) {
            Node node = getNode(id, root);
            if (null == node) {
                return new ArrayList<>();
            }
            return getDescendantNodes(node);
        }

        /**
         * 获取子孙节点
         *
         * @param root
         * @return
         */
        public static List<Node> getDescendantNodes(Node root) {
            if (null == root) {
                return new ArrayList<>();
            }
            List<Node> res = new ArrayList<>();
            Queue<Node> queue = new LinkedList<>(root.getChild());
            while (queue.size() > 0) {
                Node node = queue.poll();
                if (null != node) {
                    res.add(node);
                    if (!CollectionUtils.isEmpty(node.getChild())) {
                        queue.addAll(node.getChild());
                    }
                }
            }
            return res;
        }
    }

}
